package org.zuel.Luce.service.Impl;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.highlight.*;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.zuel.Luce.component.MyIKAnalyzer;
import org.zuel.Luce.dao.luceDao.LuceTableMapper;
import org.zuel.Luce.dao.secDao.LuceSec1Mapper;
import org.zuel.Luce.dao.secDao.LuceSec2Mapper;
import org.zuel.Luce.model.LuceSec1WithBLOBs;
import org.zuel.Luce.model.LuceSec2WithBLOBs;
import org.zuel.Luce.model.LuceTableWithBLOBs;
import org.zuel.Luce.model.TextTable;
import org.zuel.Luce.service.ILuceService;
import org.zuel.Luce.util.IndexUtil;
import org.zuel.Luce.util.ResponseUtil;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.util.*;

@Service
public class LuceService implements ILuceService {

    private LuceTableMapper luceTableMapper;
    private LuceSec1Mapper luceSec1Mapper;
    private LuceSec2Mapper luceSec2Mapper;

    private final String[] str={"title","info","text"};
    private final List<Integer> indexlist=new ArrayList<>(3);
    @Autowired
    LuceService(LuceTableMapper luceTableMapper,LuceSec1Mapper luceSec1Mapper,LuceSec2Mapper luceSec2Mapper){
        this.luceTableMapper=luceTableMapper;
        this.luceSec1Mapper=luceSec1Mapper;
        this.luceSec2Mapper=luceSec2Mapper;

        List<LuceTableWithBLOBs> list = luceTableMapper.selectToall();
        indexlist.add(list.size());
        List<LuceTableWithBLOBs> list1=luceSec1Mapper.selectToall();
        indexlist.add(list1.size());
        List<LuceTableWithBLOBs> list2=luceSec2Mapper.selectToall();
        indexlist.add(list2.size());
    }
    @Override
    public Object createIndex() throws IOException {
        List<LuceTableWithBLOBs> list1=luceSec1Mapper.selectToall();
        List<LuceTableWithBLOBs> list = luceTableMapper.selectToall();
        List<LuceTableWithBLOBs> list2=luceSec2Mapper.selectToall();
        Collection<Document> docs = new ArrayList<>();
        for (LuceTableWithBLOBs withBLOBs : list) {
            // 创建文档对象
            Document document = new Document();
            //StringField会创建索引，但是不会被分词，TextField，即创建索引又会被分词。
            document.add(new StringField("id", IndexUtil.databaseToDoc(indexlist,0,withBLOBs.getId()+1) + "", Field.Store.YES));
            document.add(new TextField("title", withBLOBs.getTitle(), Field.Store.YES));
            document.add(new StringField("url", withBLOBs.getUrl(), Field.Store.YES));
            document.add(new TextField("text", withBLOBs.getText(), Field.Store.YES));
            document.add(new TextField("info", withBLOBs.getInfo(), Field.Store.YES));
            docs.add(document);
        }
        for (LuceTableWithBLOBs tableWithBLOBs : list1) {
            // 创建文档对象
            Document document = new Document();
            //StringField会创建索引，但是不会被分词，TextField，即创建索引又会被分词。
            document.add(new StringField("id", IndexUtil.databaseToDoc(indexlist,1,tableWithBLOBs.getId()+1)+ "", Field.Store.YES));
            document.add(new TextField("title", tableWithBLOBs.getTitle(), Field.Store.YES));
            document.add(new StringField("url", tableWithBLOBs.getUrl(), Field.Store.YES));
            document.add(new TextField("text", tableWithBLOBs.getText(), Field.Store.YES));
            document.add(new TextField("info", tableWithBLOBs.getInfo(), Field.Store.YES));
            docs.add(document);
        }
        for (LuceTableWithBLOBs luceTableWithBLOBs : list2) {
            // 创建文档对象
            Document document = new Document();
            //StringField会创建索引，但是不会被分词，TextField，即创建索引又会被分词。
            document.add(new StringField("id", IndexUtil.databaseToDoc(indexlist,2,luceTableWithBLOBs.getId()+1) + "", Field.Store.YES));
            document.add(new TextField("title", luceTableWithBLOBs.getTitle(), Field.Store.YES));
            document.add(new StringField("url", luceTableWithBLOBs.getUrl(), Field.Store.YES));
            document.add(new TextField("text", luceTableWithBLOBs.getText(), Field.Store.YES));
            document.add(new TextField("info", luceTableWithBLOBs.getInfo(), Field.Store.YES));
            docs.add(document);
        }
        // 索引目录类,指定索引在硬盘中的位置，我的设置为D盘的indexDir文件夹
        Directory directory = FSDirectory.open(FileSystems.getDefault().getPath("D:\\Luce\\index"));
        // 引入IK分词器
        Analyzer analyzer = new MyIKAnalyzer();
        // 索引写出工具的配置对象，这个地方就是最上面报错的问题解决方案
        IndexWriterConfig conf = new IndexWriterConfig(analyzer);
        // 设置打开方式：OpenMode.APPEND 会在索引库的基础上追加新索引。OpenMode.CREATE会先清空原来数据，再提交新的索引
        conf.setOpenMode(IndexWriterConfig.OpenMode.CREATE);
        // 创建索引的写出工具类。参数：索引的目录和配置信息
        IndexWriter indexWriter = new IndexWriter(directory, conf);
        // 把文档集合交给IndexWriter
        indexWriter.addDocuments(docs);
        // 提交
        indexWriter.commit();
        // 关闭
        indexWriter.close();
        return ResponseUtil.ok("success");
    }
    @Override
    public Object updateIndex() throws IOException {
        return null;
    }

    @Override
    public Object updateOne(TextTable textTable) throws IOException {
        return null;
    }

    @Override
    public Object add() {
        return null;
    }

    @Override
    public Object search(String seach) throws IOException, ParseException, InvalidTokenOffsetsException {
        System.out.println("查询输入："+seach);
        Directory directory = FSDirectory.open(FileSystems.getDefault().getPath("D:\\Luce\\index"));
        // 索引读取工具
        IndexReader reader = DirectoryReader.open(directory);
        // 索引搜索工具
        IndexSearcher searcher = new IndexSearcher(reader);
        // 创建查询解析器,两个参数：默认要查询的字段的名称，分词器
        MultiFieldQueryParser parser = new MultiFieldQueryParser(str, new MyIKAnalyzer());
        // 创建查询对象
        Query query = parser.parse(seach);

        //获取高亮显示
        SimpleHTMLFormatter simpleHTMLFormatter = new SimpleHTMLFormatter("<span style='color:red'>", "</span>");
        Highlighter highlighter = new Highlighter(simpleHTMLFormatter, new QueryScorer(query));
        Fragmenter fragmenter = new SimpleFragmenter(80);   //高亮后的段落范围在80字内
        highlighter.setTextFragmenter(fragmenter);

        // 获取十条记录
        TopDocs topDocs = searcher.search(query, 10);
        // 获取总条数
        System.out.println("本次搜索共找到" + topDocs.totalHits + "条数据");
        // 获取得分文档对象（ScoreDoc）数组.SocreDoc中包含：文档的编号、文档的得分
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;

        List<LuceTableWithBLOBs> list = new ArrayList<>();
        for (ScoreDoc scoreDoc : scoreDocs) {
            // 取出文档编号
            int docID = scoreDoc.doc;
            System.out.println("scoreDoce number:"+docID+"and score"+scoreDoc.score);
            // 根据编号去找文档
            Document doc = reader.document(docID);
            if(docID==0){
                return list;
            }
            System.out.println(doc);
            List<Integer> list1=IndexUtil.docToDatabase(indexlist,docID+1);
            //从数据库中查询正文
            LuceTableWithBLOBs textTable;
            if(list1.get(0)==0){
                textTable = luceTableMapper.selectByPrimaryKey(list1.get(1));
            }
            else if(list1.get(0)==1){
                textTable =luceSec1Mapper.selectByPrimaryKey(list1.get(1));
            }
            else{
                textTable =luceSec2Mapper.selectByPrimaryKey(list1.get(1));
            }
            //处理高亮字段显示
            String title = highlighter.getBestFragment(new MyIKAnalyzer(), "title",doc.get("title"));
            if(title!=null){
                textTable.setTitle(title);
            }
            String info = highlighter.getBestFragment(new MyIKAnalyzer(), "info",doc.get("info"));
            if(info!=null){
                textTable.setInfo(info);
            }
            list.add(textTable);
        }
        System.out.println(list);
        System.out.println();
        return ResponseUtil.ok(list);
    }
    @Override
    public Object delete() {
        return null;
    }
}
